/**
 * Project:   warnme-server
 * File:      EventServiceImpl.java
 * License: 
 *            This file is licensed under GNU General Public License version 3
 *            http://www.gnu.org/licenses/gpl-3.0.txt
 *
 * Copyright: Bartlomiej Gebski [ b.k.gebski@gmail.com ]
 * Date:      Apr 3, 2014
 */

package dtu.ds.warnme.services.impl;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import dtu.ds.warnme.dao.EventsDao;
import dtu.ds.warnme.exceptions.impl.ServiceException;
import dtu.ds.warnme.model.impl.EventEntity;
import dtu.ds.warnme.model.impl.EventType;
import dtu.ds.warnme.services.EventsService;
import dtu.ds.warnme.utils.LocationUtils;

/**
 * @author Bartlomiej Gebski
 */
@Transactional(propagation = Propagation.REQUIRES_NEW)
public class EventsServiceImpl implements EventsService {

	public final static Float SOURROUNDING_MARGIN = 200f;

	@Autowired
	private EventsDao eventsDao;

	/*
	 * (non-Javadoc)
	 * @see dtu.ds.warnme.services.EventsService#downvoteEvent(java.lang.String)
	 */
	@Override
	public void downvoteEvent(String id) throws ServiceException {
		EventEntity retrieved = eventsDao.getById(id);
		if (retrieved == null) {
			throw new ServiceException("Cannot downvote - Event with this ID does not exist!",
			        "exceptions.serviceExceptions.events.notExistId");
		}
		retrieved.setReportsCount(retrieved.getReportsCount() - 1);
		eventsDao.update(retrieved);

	}

	/*
	 * (non-Javadoc)
	 * @see dtu.ds.warnme.services.EventsService#getEvent(java.lang.String)
	 */
	@Override
	public EventEntity getEvent(String id) throws ServiceException {
		if (StringUtils.isBlank(id)) {
			throw new ServiceException("You can't modify the stats of \"nothing\".", "exceptions.serviceExceptions.events.notExistId");
		}

		EventEntity byId = eventsDao.getById(id);

		if (byId == null) {
			throw new ServiceException("Event with this ID does not exist!", "exceptions.serviceExceptions.events.notExistId");
		}

		return byId;
	}

	/*
	 * (non-Javadoc)
	 * @see dtu.ds.warnme.services.EventsService#getEvents(java.lang.Double, java.lang.Double, java.lang.Double, java.lang.Integer)
	 */
	@Override
	public List<EventEntity> getEvents(Float latitude, Float longitude, Float bearing, Float radius, EventType[] types) {
		Float northMargin, eastMargin, southMargin, westMargin;

		northMargin = southMargin = eastMargin = westMargin = SOURROUNDING_MARGIN;

		if (bearing >= 0 && bearing < 90) {
			northMargin = radius;
			eastMargin = radius;
		} else if (bearing >= 90 && bearing < 180) {
			eastMargin = radius;
			southMargin = radius;
		} else if (bearing >= 180 && bearing < 270) {
			southMargin = radius;
			westMargin = radius;
		} else if (bearing >= 270 && bearing < 360) {
			westMargin = radius;
			northMargin = radius;
		} else {
			northMargin = southMargin = eastMargin = westMargin = radius;
		}

		Float latMeter = 1f / 110540f;
		Float longMeter = 1f / (float) (111320 * Math.cos(latitude));

		northMargin *= latMeter;
		southMargin *= latMeter;
		westMargin *= longMeter;
		eastMargin *= longMeter;

		Float nLat = latitude + northMargin;
		Float sLat = latitude - southMargin;
		Float eLng = longitude + eastMargin;
		Float wLng = longitude - westMargin;

		return eventsDao.getNearestEvents(nLat, sLat, eLng, wLng, types);
	}

	/*
	 * (non-Javadoc)
	 * @see dtu.ds.warnme.services.EventService#registerEvent(dtu.ds.warnme.model.impl.EventEntity)
	 */
	@Override
	public boolean registerEvent(EventEntity event) throws ServiceException {
		if (!LocationUtils.isLatitudeValid(event.getLatitude())) {
			throw new ServiceException("Latitude out of range", "exceptions.serviceExceptions.events.latitudeOutOfRangeException");
		}
		if (!LocationUtils.isLongitudeValid(event.getLongitude())) {
			throw new ServiceException("Longitude out of range", "exceptions.serviceExceptions.events.longitudeOutOfRangeException");
		}

		eventsDao.create(event);
		return true;
	}

	/*
	 * (non-Javadoc)
	 * @see dtu.ds.warnme.services.EventsService#upvoteEvent(java.lang.String)
	 */
	@Override
	public void upvoteEvent(String id) throws ServiceException {
		EventEntity retrieved = eventsDao.getById(id);
		if (retrieved == null) {
			throw new ServiceException("Cannot upvote - Event with this ID does not exist!",
			        "exceptions.serviceExceptions.events.notExistId");
		}
		retrieved.setReportsCount(retrieved.getReportsCount() + 1);
		eventsDao.update(retrieved);
	}

}
